home *** CD-ROM | disk | FTP | other *** search
- Chapter 5 - Modula-2 Procedures
-
-
- In order to define the procedure, we will need to lay
- some groundwork in the form of a few definitions.
-
- Program Heading - This is the easiest part since it is
- only one line, at least it has been in all of our
- programs up to this point. It is simply the MODULE
- line, and it never needs to be any more involved than
- it has been up to this point, except for one small
- addition which we will cover in a later chapter.
-
- Declaration Part - This is the part of the Modula-2 source
- code in which all constants, variables, and other user
- defined auxiliary operations are defined. In some of
- the programs we have examined, there have been one or
- more VAR declarations and in one case a constant was
- declared. These are the only components of the
- declaration part we have used up to this time. There
- are actually four components in the declaration part,
- and the procedures make up the fourth part. We will
- cover the others in the next chapter.
-
- Statement Part - This is the last part of any Modula-2
- program, and it is what we have been calling the main
- program. It always exists bounded by the reserved
- words BEGIN and END just as it has in all of our
- examples to this point.
-
- It is very important that you grasp the above
- definitions because we will be referring to them constantly
- during this chapter, and throughout the remainder of this
- tutorial. With that introduction, let us look at our first
- Modula-2 program with a procedure in it. It will, in fact,
- have three procedures.
-
- WHAT IS A PROCEDURE?
-
- A Procedure is a group of statements, either predefined
- by the compiler writer, or defined by you, that can be
- called upon to do a specific job. In this chapter we will
- see how to write and use a procedure. During your
- programming in the future, you will use many procedures. In
- fact, you have already used some because the "WriteString",
- "WriteLn", etc procedures you have been using are predefined
- procedures.
-
- Load and display the program named PROCED1.MOD for your
- first look at a user defined procedure. In this program, we
- have the usual header with one variable defined. Ignore the
- header and move down to the main program beginning with line
- 26. We will come back to all of the statements prior to the
- main program in a few minutes.
-
-
- Page 29
-
-
-
-
-
-
-
-
-
- Chapter 5 - Modula-2 Procedures
-
-
-
- The main program is very easy to understand based on
- all of your past experience with Modula-2. First we somehow
- write a header (WriteHeader), then write a message out 8
- times (WriteMessage), and finally we write an ending out
- (WriteEnding). Notice that with the long names for the
- parts, no comments are needed, the program is self
- documenting. The only problem we have is, how does the
- computer actually do the three steps we have asked for.
- That is the purpose for the 3 procedures defined earlier
- starting in lines 8, 14, and 20. Modula-2 requires that
- nothing can be used until it has been defined, so the
- procedures are required to be defined prior to the main
- program. This may seem a bit backward to you if you are
- experienced in some other languages like FORTRAN, BASIC, or
- C, but it will make sense eventually.
-
- HOW DO WE DEFINE A PROCEDURE?
-
- We will begin with the PROCEDURE at line 8. First we
- must use the reserved word PROCEDURE followed by the name we
- have chosen for our procedure, in this case "WriteHeader"
- which is required to follow all of the rules for naming an
- identifier. Following the PROCEDURE line, we can include
- more IMPORT lists, define variables, or any of several other
- things. We will go into a complete definition of this part
- of the program in the next chapter. I just wanted to
- mention that other quantities could be inserted here. We
- finally come to the procedure body which contains the actual
- instructions we wish to execute in the procedure. In this
- case, the procedure body is very simple, containing only a
- "WriteString" and a "WriteLn" instruction, but it could have
- been as complex as we needed to make it.
-
- At the end of the procedure, we once again use the
- reserved word END followed by the same name as we defined
- for the procedure name. In the case of a procedure, the
- final name is followed by a semicolon instead of a period.
- Other than this small change, a procedure definition is
- identical to that of the program itself.
-
- When the main program comes to the "WriteHeader"
- statement, it knows that it is not part of its standard list
- of executable instructions, so it looks for the user defined
- procedure by that name. When it finds it, it transfers
- control of the program sequence to there, and begins
- executing those instructions. When it executes all of the
- instructions in the procedure, it finds the END statement of
- the procedure and returns to the next statement in the main
- program. When the main program finally runs out of things
- to do, it finds the END statement and terminates.
-
-
- Page 30
-
-
-
-
-
-
-
-
-
- Chapter 5 - Modula-2 Procedures
-
-
-
- As the program executes the FOR loop, it is required to
- call the "WriteMessage" procedure 8 times, each time writing
- its message on the monitor, and finally it finds and
- executes the "WriteEnding" procedure. This should be very
- straightforward and should pose no real problem for you to
- understand. When you think you understand what it should
- do, compile and run it to see if it does.
-
- NOW FOR A PROCEDURE THAT USES SOME DATA
-
- The last program was interesting to show you how a
- procedure works but if you would like to see how to get some
- data into the procedure, load and display the program named
- PROCED2.MOD. We will once again go straight to the program
- starting in line number 25. We immediately notice that the
- program is nothing more than one big FOR loop which we go
- through 3 times. Each time through the loop we call several
- procedures, some that are system defined, and some that are
- user defined. This time instead of the simple procedure
- name, we have a variable in the parentheses behind the
- variable name. In these procedures, we will take some data
- with us to the procedures, when we call them, just like we
- have been doing with the "WriteString" and "WriteInt"
- procedures.
-
- We will take some data to the procedure named
- "PrintDataOut" where it will be printed. The procedure
- "PrintDataOut" starting in line 9 also contains a pair of
- parentheses with a variable named "Puppy" which is of type
- INTEGER. This says that it is expecting a variable to be
- passed to it from the calling program and it expects the
- variable to be of type INTEGER. Back to the main program we
- see, on line 28, that the program did make the call to the
- procedure with a variable named "Thing" which is an INTEGER
- type variable, so everything is fine. The procedure prefers
- to call the variable passed to it "Puppy" but that is
- perfectly acceptable, it is the same variable. The
- procedure writes the value of "Puppy", which is really the
- variable "Thing" in the main program, in a line with an
- identifying string, then changes the value of "Puppy" before
- returning to the main program.
-
- Upon returning to the main program, we print out
- another line with three separate parts (notice the indenting
- and the way it makes the program more readable), then calls
- the next procedure "PrintAndModify" which appears to do the
- same thing as the last one. Indeed, studying the procedure
- itself leads you to believe they are the same, except for
- the fact that this one prefers to use the name "Cat" for a
- variable name. There is one subtle difference in this
-
-
- Page 31
-
-
-
-
-
-
-
-
-
- Chapter 5 - Modula-2 Procedures
-
-
- procedure, the reserved word VAR in the header, line 17.
-
- CALL BY VALUE & CALL BY REFERENCE
-
- In the first procedure, the word VAR was omitted. This
- is a signal to the compiler that this procedure will not
- actually receive the variable reference, instead it will
- receive a local copy of the variable which it can use in
- whatever way it needs to. When it is finished, however, it
- can not return any changes in the variable to the main
- program because it can only work with its copy of the
- variable. This is therefore a one-way variable, it can only
- pass data to the procedure. This is sometimes called a
- "call by value" or a "value parameter" in literature about
- Modula-2.
-
- In the second procedure, the word VAR was included.
- This signals the compiler that the variable in this
- procedure is meant to be actually passed to the procedure,
- and not just the value of the variable. The procedure can
- use this variable in any way it desires, and since it has
- access to the variable in the main program, it can alter it
- if it so desires. This is therefore a two-way variable, it
- can pass data from the main program to the procedure and
- back again. This is sometimes called a "call by reference"
- or a "variable parameter" in literature about Modula-2.
-
- WHICH SHOULD BE USED?
-
- It is up to you to decide which of the two parameter
- passing schemes you should use for each application. The
- "two-way" scheme seems to give the greatest flexibility, so
- your first thought is to simply use it everywhere. But that
- is not a good idea because it gives every procedure the
- ability to corrupt your main program variables. In
- addition, if you use a "call by value" in the procedure
- definition, you have the ability to call the procedure with
- a constant in that part of the call. A good example is
- given in lines 12, 20, 30, 34, and 38 of the present
- program. If "WriteInt" were defined with a "call by
- reference", we could not use a constant here, but instead
- would have to set up a variable, assign it the desired
- value, then use the variable name instead of the 5. There
- are other considerations but they are beyond the level of
- our study at this point.
-
- BACK TO THE PROGRAM ON DISPLAY, PROCED2
-
- We have already mentioned that both of the procedures
- modify their respective local variables, but due to the
- difference in "call by value" in the first, and "call by
-
-
- Page 32
-
-
-
-
-
-
-
-
-
- Chapter 5 - Modula-2 Procedures
-
-
- reference" in the second, only the second can actually get
- the modified data back to the calling program. This is why
- they are named the way they are. One other thing should be
- mentioned. Since it is not good practice to modify the
- variable used to control the FOR loop, (and downright
- erroneous in many cases) we make a copy of it and call it
- "Thing" for use in the calls to the procedures. Based on
- all we have said above, you should be able to figure out
- what the program will do, then compile and run it.
-
- SEVERAL PARAMETERS PASSED AT ONCE
-
- Load and display the program named PROCED3.MOD for an
- example of a procedure definition with more than one
- variable being passed to it. In this case four parameters
- are passed to this procedure. Three of the parameters are
- one-way and one is a two-way parameter. In this case we
- simply add the three numbers and return it to the main
- program. Good programming practice would dictate the
- placement of the single "call by reference" by itself and
- the others grouped together, but it is more important to
- demonstrate to you that they can be in any order you desire.
- This is a very straightforward example that should pose no
- problem to you. Compile and run it.
-
- SCOPE OF VARIABLES
-
- Load and display the program PROCED4.MOD for a program
- which can be used to define scope of variables or where
- variables can be used in a program. The three variables
- defined in lines 6, 7, and 8, are of course available in the
- main program because they are defined prior to it. The two
- variables defined in the procedure are available within the
- procedure because that is where they are defined. However,
- because the variable "Count" is defined both places, it is
- two completely separate variables. The main program can
- never use the variable "Count" defined in the procedure, and
- the procedure can never use the variable "Count" defined in
- the main program. They are two completely separate and
- unique variables with no ties between them. This is useful
- because when your programs grow, you can define a variable
- in a procedure, use it in whatever way you wish, and not
- have to worry that you are corrupting some other "global"
- variable. The variables in the main program are called
- "global variables" because they are available everywhere.
-
- In addition to the above scope rules, the variable
- named "Apple" in the procedure, is not available to the main
- program. Since it is defined in the procedure it can only
- be used in the procedure. The procedure effectively builds
- a wall around the variable "Apple" and its own "Count" so
-
-
- Page 33
-
-
-
-
-
-
-
-
-
- Chapter 5 - Modula-2 Procedures
-
-
- that neither is available outside of the procedure. We will
- see in the next chapter that procedures can be "nested"
- leading to further hiding of variables. This program is
- intended to illustrate the scope of variables, and it would
- be good for you to study it, then compile and run it.
-
- A PROCEDURE CAN CALL ANOTHER PROCEDURE
-
- Load and display the program named PROCED5.MOD for an
- example of procedures that call other procedures. Study of
- this program will reveal that procedure "Three" starting on
- line 19 calls procedure "Two" which in turn calls procedure
- "One". The main program calls all three, one at a time, and
- the result is a succession of calls which should be rather
- easy for you to follow. The general rule is, "any program
- or procedure can call any other procedure that has been
- previously defined, and is visible to it." (We will say
- more about visibility later.) Study this program then
- compile and run it.
-
- A FUNCTION PROCEDURE
-
- Load and display the program named FUNCTION.MOD for an
- example of a "Function Procedure". This contains a
- procedure very much like the ones we have seen so far with
- one difference. In the procedure heading, line 6, there is
- an added ": INTEGER" at the end of the argument list. This
- is a signal to the system that this procedure is a "function
- procedure" and it therefore returns a value to the calling
- program in a way other than that provided for by parameter
- references as we have used before. In fact, this program
- returns a single data value that will be of type INTEGER.
-
- In line 16 of the calling program, we find the call to
- the procedure which looks like the others we have used
- except that it is used in an assignment statement as though
- it is an INTEGER type variable. This is exactly what it is
- and when the call is completed, the "QuadOfSum(Dogs,Cats)"
- will be replaced by the answer and then assigned to the
- variable "Feet". The entire call can therefore be used
- anyplace in a program where it is legal to use an INTEGER
- type variable. This is therefore a single value return and
- can be very useful in the right situation. In one of the
- earlier program, we used the "sin" and "cos" function
- procedures and this is exactly what they were.
-
- One additional point must be made here. If a function
- procedure does not require any parameters, the call to it
- must include empty parentheses, and the definition of the
- procedure must include empty parentheses also. This is by
- definition of the Modula-2 language.
-
-
- Page 34
-
-
-
-
-
-
-
-
-
- Chapter 5 - Modula-2 Procedures
-
-
-
- In the procedure, we had to do one thing slightly
- different in order to get the return value and that was to
- use the RETURN reserved word. Whenever we have completed
- the desired calculations or whatever we need to do, we put
- the result that is to be returned to the main program in the
- parentheses following the RETURN and the procedure will
- terminate, return to the calling program, and take the value
- with it as the answer. Due to decision making, we may have
- several RETURN statements in the procedure but only one will
- be exercised with each call. It is an error to come to the
- END statement of a function procedure since that would
- constitute a return without the benefit of the RETURN
- statement, and no value would be returned to the calling
- program.
-
- WHAT IS RECURSION?
-
- Recursion is simply a procedure calling itself. If you
- have never been introduced to recursion before, that
- definition sounds too simple but that is exactly what it is.
- You have probably seen a picture containing a picture of
- itself. The picture in the picture also contains a picture
- of itself, the end result being an infinity of pictures.
- Load the file named RECURSON.MOD for an example of a program
- with recursion.
-
- In the main program, "Count" is set to 7 and the
- procedure is called taking along "Count" as a parameter. In
- the procedure, we display a line containing the value of the
- variable, now called "Index", and decrement it. If the
- variable is greater than zero, we call the same procedure
- again, this time entering it with the value of 6. It would
- be reasonably correct to think of the system as creating
- another copy of the procedure for this call. The variable
- "Index" would be reduced to 5, and another copy of the
- procedure would be called. Finally, the variable would be
- reduced to zero and the return path from procedure to
- procedure would be taken until the main program would be
- reached, where the program would terminate.
-
- Rather than making a complete new copy of the procedure
- for each recursive call, the same code would be run each
- time through and all of the data would be stored away on the
- "stack" each time through. You have no need to worry about
- this because it is all taken care of for you by the system.
- You simply call the same procedure as though it were any
- other procedure and the system will worry about all of the
- details except for one. It is up to you to see that there
- is some mechanism by which the process will terminate. If
- there were no decrementing statement in the procedure, this
-
-
- Page 35
-
-
-
-
-
-
-
-
-
- Chapter 5 - Modula-2 Procedures
-
-
- program would never reach an end and the stack would
- overflow, resulting in an error message and termination of
- the program. It would be worth your time to remove the
- decrementing statement and observe this, after you compile
- and run it the way it is now.
-
- Recursion can be very useful for those problems that
- warrant its use. This example is a very stupid use of
- recursion, but is an excellent method for giving an example
- of a program with recursion that is simple and easy to
- understand.
-
- DIRECT AND INDIRECT RECURSION
-
- This example uses direct recursion because the
- procedure calls itself directly. It is also possible to use
- indirect recursion where procedure "A" calls "B", "B" calls
- "A", etc. Either method is available and useful depending
- on the particular circumstances.
-
-
- PROGRAMMING EXERCISES
-
- 1. Write a program to write your name, address, and phone
- number on the monitor with each line in a different
- procedure.
-
- 2. Add a statement to the procedure in RECURSON to display
- the value of "Index" after the call to itself so you
- can see the value increasing as the recurring calls are
- returned to the next higher level.
-
- 3. Rewrite TEMPCONV from chapter 4 putting the centigrade
- to farenheit formula in a function procedure.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Page 36
-
-